/**
 * @file	bleuart_service.c
 * @author	chipsea
 * @brief	
 * @version	0.1
 * @date	2020-11-30
 * @copyright Copyright (c) 2020, CHIPSEA Co., Ltd.
 * @note
 */

/*********************************************************************
 * INCLUDES
 */
#include "sdk_config.h"
#include "att.h"
#include "log.h"
#include "OSAL.h"
#include "gatt.h"
#include "error.h"
#include "linkdb.h"
#include "gatt_uuid.h"
#include "gattservapp.h"
#include "global_config.h"
#include "bleuart_service.h"




#define RAWPASS_RX_BUFF_SIZE	1

#define RAWPASS_TX_VALUE_HANDLE	2
#define RAWPASS_RX_VALUE_HANDLE	5

#define UUID_16BIT
#ifdef UUID_16BIT
///< Rawpass GATT Profile Service UUID
CONST uint8 bleuart_ServiceUUID[ATT_BT_UUID_SIZE] =
{ 
	LO_UINT16(BLE_UART_SERV_UUID), HI_UINT16(BLE_UART_SERV_UUID)
};

///< Characteristic tx uuid
CONST uint8 bleuart_TxCharUUID[ATT_BT_UUID_SIZE] =
{ 
	LO_UINT16(BLE_UART_CHAR1_UUID), HI_UINT16(BLE_UART_CHAR1_UUID)
};
///< Characteristic rx uuid
CONST uint8 bleuart_RxCharUUID[ATT_BT_UUID_SIZE] =
{ 
	LO_UINT16(BLE_UART_CHAR2_UUID), HI_UINT16(BLE_UART_CHAR2_UUID)
};
#else
///< Rawpass GATT Profile Service UUID
CONST uint8 bleuart_ServiceUUID[ATT_UUID_SIZE] =
{
    0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80, 
    0x00, 0x10, 0x00, 0x00, 0xF0, 0xFF, 0x00, 0x00
};

///< Characteristic tx uuid
CONST uint8 bleuart_TxCharUUID[ATT_UUID_SIZE] =
{ 
	0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80, 
    0x00, 0x10, 0x00, 0x00, 0xF1, 0xFF, 0x00, 0x00
};
///< Characteristic rx uuid
CONST uint8 bleuart_RxCharUUID[ATT_UUID_SIZE] =
{ 
	0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80, 
    0x00, 0x10, 0x00, 0x00, 0xF2, 0xFF, 0x00, 0x00
};
#endif

/*********************************************************************
 * LOCAL VARIABLES
 */
static bleuart_ProfileChangeCB_t bleuart_AppCBs = NULL;

/*********************************************************************
 * Profile Attributes - variables
 */
///< Profile Service attribute
#ifdef UUID_16BIT
static CONST gattAttrType_t bleuart_Service = { ATT_BT_UUID_SIZE, bleuart_ServiceUUID };
#else
static CONST gattAttrType_t bleuart_Service = { ATT_UUID_SIZE, bleuart_ServiceUUID };
#endif

///< Profile Characteristic 1 Properties
static uint8 bleuart_TxCharProps = GATT_PROP_NOTIFY;

///< Characteristic 1 Value
static uint8 bleuart_TxCharValue = 0;

///< Simple Profile Characteristic 1 User Description
static gattCharCfg_t bleuart_TxCCCD;

///< Profile Characteristic 2 Properties
static uint8 bleuart_RxCharProps =   GATT_PROP_WRITE_NO_RSP;

///< Characteristic 2 Value
static uint8 bleuart_RxCharValue[RAWPASS_RX_BUFF_SIZE];

/*********************************************************************
 * Profile Attributes - Table
 */
static gattAttribute_t bleuart_ProfileAttrTbl[] = 
{
	///< Simple Profile Service
	{
		{ ATT_BT_UUID_SIZE, primaryServiceUUID }, 	/* type */
		GATT_PERMIT_READ,                         	/* permissions */
		0,                                        	/* handle */
		(uint8 *)&bleuart_Service            		/* pValue */
	},

	///< Characteristic 1 Declaration
	{
		{ ATT_BT_UUID_SIZE, characterUUID },
		GATT_PERMIT_READ,
		0,
		&bleuart_TxCharProps
	},

	///< Characteristic Value 1
	{
    #ifdef UUID_16BIT
		{ ATT_BT_UUID_SIZE, bleuart_TxCharUUID },
    #else
        { ATT_UUID_SIZE, bleuart_TxCharUUID },
    #endif
		0,
		0,
		(uint8 *)&bleuart_TxCharValue
	},

	///< Characteristic 1 User Description
	{
		{ ATT_BT_UUID_SIZE, clientCharCfgUUID },
		GATT_PERMIT_READ|GATT_PERMIT_WRITE,
		0,
		(uint8*)&bleuart_TxCCCD
	},

	///< Characteristic 2 Declaration
	{
		{ ATT_BT_UUID_SIZE, characterUUID },
		GATT_PERMIT_READ,
		0,
		&bleuart_RxCharProps
	},

	///< Characteristic Value 2
	{
    #ifdef UUID_16BIT
		{ ATT_BT_UUID_SIZE, bleuart_RxCharUUID },
    #else
        { ATT_UUID_SIZE, bleuart_RxCharUUID },
    #endif
		GATT_PERMIT_WRITE,
		0,
		&bleuart_RxCharValue[0]
	}
};

/*********************************************************************
 * LOCAL FUNCTIONS
 */
static bStatus_t bleuart_WriteAttrCB( uint16 connHandle, gattAttribute_t *pAttr,
									  uint8 *pValue, uint16 len, uint16 offset );
static void bleuart_HandleConnStatusCB( uint16 connHandle, uint8 changeType );

/*********************************************************************
 * PROFILE CALLBACKS
 */
CONST gattServiceCBs_t bleuart_ProfileCBs =
{
	NULL,
	bleuart_WriteAttrCB, // Write callback function pointer
	NULL                 // Authorization callback function pointer
};

/**
 * @fn      bleuart_AddService
 * @brief   Peripheral initialization
 * @param   cb
 * @return  none
 */
bStatus_t bleuart_AddService( bleuart_ProfileChangeCB_t cb)
{
	uint8 status = SUCCESS;

	// Register with Link DB to receive link status change callback
	VOID linkDB_Register( bleuart_HandleConnStatusCB  );  

	bleuart_TxCCCD.connHandle = INVALID_CONNHANDLE;
	bleuart_TxCCCD.value = 0;
	// Register GATT attribute list and CBs with GATT Server App
	status = GATTServApp_RegisterService( bleuart_ProfileAttrTbl, 
										  GATT_NUM_ATTRS( bleuart_ProfileAttrTbl ),
										  &bleuart_ProfileCBs );
	bleuart_AppCBs = cb;

	return ( status );
}

/**
 * @fn      bleuart_WriteAttrCB
 * @brief   
 * @param   cb
 * @return  none
 */
static bStatus_t bleuart_WriteAttrCB( uint16 connHandle, gattAttribute_t *pAttr,
									  uint8 *pValue, uint16 len, uint16 offset )
{
    bStatus_t status = SUCCESS;
    //uint8 notifyApp = 0xFF;
    // If attribute permissions require authorization to write, return error
    if ( gattPermitAuthorWrite( pAttr->permissions ) )
    {
        // Insufficient authorization
        return ( ATT_ERR_INSUFFICIENT_AUTHOR );
    }
  
    if ( pAttr->type.len == ATT_BT_UUID_SIZE )
    {
        // 16-bit UUID
        uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]);
        if(uuid == GATT_CLIENT_CHAR_CFG_UUID)
        {
          status = GATTServApp_ProcessCCCWriteReq( connHandle, pAttr, pValue, len,
                                                   offset, GATT_CLIENT_CFG_NOTIFY );
          if ( status == SUCCESS && bleuart_AppCBs)
          {
            uint16 charCfg = BUILD_UINT16( pValue[0], pValue[1] );
            bleuart_Evt_t evt;
          
            
            evt.ev = (charCfg == GATT_CFG_NO_OPERATION)?bleuart_EVT_TX_NOTI_DISABLED:bleuart_EVT_TX_NOTI_ENABLED;
            bleuart_AppCBs(&evt);
			LOG("CCC:%d\n",charCfg);
          }
        }
    }
    if(pAttr->handle == bleuart_ProfileAttrTbl[RAWPASS_RX_VALUE_HANDLE].handle)
    {
      if(bleuart_AppCBs){
        bleuart_Evt_t evt;
        evt.ev = bleuart_EVT_BLE_DATA_RECIEVED;
        evt.param = (uint16_t)len;
        evt.data = pValue;
        bleuart_AppCBs(&evt);
      }
    }
    
    return ( status );
}

/**
 * @fn      bleuart_HandleConnStatusCB
 * @brief   
 * @param   cb
 * @return  none
 */
static void bleuart_HandleConnStatusCB ( uint16 connHandle, uint8 changeType )
{ 
	///< Make sure this is not loopback connection
	if( connHandle != LOOPBACK_CONNHANDLE )
	{
		///< Reset Client Char Config if connection has dropped
		if( ( changeType == LINKDB_STATUS_UPDATE_REMOVED )      ||
			( ( changeType == LINKDB_STATUS_UPDATE_STATEFLAGS ) && 
			( !linkDB_Up( connHandle ) ) ) )
		{
			bleuart_TxCCCD.value = 0;
		}
	}
}

/**
 * @fn      bleuart_Notify
 * @brief   
 * @param   cb
 * @return  none
 */
bStatus_t bleuart_Notify( uint16 connHandle, attHandleValueNoti_t *pNoti)
{
	uint16 value = bleuart_TxCCCD.value;

	///< If notifications enabled
	if( value & GATT_CLIENT_CFG_NOTIFY )
	{
		///< Set the handle
		pNoti->handle = bleuart_ProfileAttrTbl[RAWPASS_TX_VALUE_HANDLE].handle;

		///< Send the Indication
		return GATT_Notification( connHandle, pNoti, FALSE);
	}
	return bleIncorrectMode;
}
